home *** CD-ROM | disk | FTP | other *** search
/ AppleScript - The Beta Release / AppleScript - The Beta Release.iso / Documentation / develop / Apple Event Objects and You / Apple Event Objects (code) / cScrapItem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-08  |  12.2 KB  |  380 lines  |  [TEXT/KAHL]

  1.  
  2.  
  3. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  4. /*                                                                                   */
  5. /*    This file contains the code for implementing the cScrapItem AE object.                */
  6. /*                                                                                   */
  7. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  8.  
  9. #include "AEPackObject.h"
  10. #include "AEObjects.h"
  11. #include "AERegistry.h"
  12. #include <packages.h>
  13. #include "ScriptScrap.h"
  14. #include "Prototypes.h"
  15.  
  16.  
  17.  
  18. /* Object from container accessors */
  19.  
  20. pascal    OSErr ItemFromEntryAccessor(DescType desiredClass,
  21.             const AEDesc *container, DescType containerClass, DescType keyForm,
  22.             const AEDesc *keyData, AEDesc *value, long LongInt)
  23. {
  24.     OSErr        err;
  25.     ResType        itemType;
  26.     Handle        dummyHandle;
  27.  
  28.     /* Since each scrapbook entry is comprised of a set of resources (a/k/a "items", in */
  29.     /* this application's parlance), and the resources aren't kept in any particular     */
  30.     /* order, that makes asking for a particular item difficult. We'll support formName */
  31.     /* (where the name is the 4-byte resource type), or a custom form called "type"     */
  32.     /* (again the 4 byte type) _only_.                                                    */
  33.  
  34.     /* We won't support asking for item 1, item 2 (or first/last/middle) because we     */
  35.     /* would have to extend the scrapbook's file format to support such orderings, and  */
  36.     /* there's no guarantee our extensions would be valid after the scrapbook DA uses   */
  37.     /* the scrapbook file.                                                                */
  38.     
  39.     /* Handle 4 character "names" and/or type codes */
  40.     if ((keyForm == formName) || (keyForm == 'type')) {
  41.         
  42.         /* We have a valid key form. Now see if the data is good */
  43.         if ((keyData->descriptorType == typeChar) || (keyData->descriptorType == typeType)) {
  44.             
  45.             /* It's a valid type, so see if the data size is right */
  46.             if (GetHandleSize(keyData->dataHandle) == sizeof(ResType)) {
  47.                 
  48.                 /* We have the right number of bytes, so extract the data */
  49.                 itemType = **(ResType**)(keyData->dataHandle);
  50.  
  51.                 /* Make sure that the specified item actually exists */
  52.                 SetResLoad(false);
  53.                 UseResFile(tokenFRefNum(*container));
  54.                 dummyHandle = Get1Resource(itemType, tokenResID(*container));
  55.                 SetResLoad(true);
  56.                 if (dummyHandle == NULL)
  57.                     err = errAENoSuchObject;
  58.                 else {
  59.                     /* Build a token by duplicating the container and filling in a */
  60.                     /* few more fields.                                               */
  61.                     err = AEDuplicateDesc(container, value);
  62.                     tokenDispatchClass(*value) = cScrapItem;
  63.                     tokenFlags(*value) = kObjectToken;
  64.                     tokenItemType(*value) = itemType;
  65.                     value->descriptorType = cScrapItem;
  66.                 }
  67.             }
  68.             else
  69.                 err = errAENoSuchObject;
  70.         } 
  71.         else
  72.             err = errAENoSuchObject;
  73.     }
  74.     else
  75.         err = errAEBadKeyForm;
  76.  
  77.     return err;
  78. }    /*  ItemfromEntryAccessor */
  79.  
  80.  
  81.  
  82. /* Property from object accessor */
  83. pascal    OSErr PropertyFromItemAccessor ( DescType desiredClass,
  84.             const AEDesc *container, DescType containerClass, DescType keyForm,
  85.             const AEDesc *keyData, AEDesc *returnedToken, long refCon )
  86. {
  87.     OSErr        err = noErr;
  88.     ourToken    tokenBody;
  89.     DescType    requestedProperty;
  90.     
  91.     /* Copy the container token and change the copy to represent a property.                         */
  92.     /* The actual reading and writing of the data is done in the token handlers. */
  93.     if ((keyForm != formPropertyID) || (keyData->descriptorType != typeType))
  94.         return errAECantSupplyType;
  95.  
  96.     requestedProperty = **(DescType**)keyData->dataHandle;
  97.     
  98.     /* Check to see if this is a legal property code for this object class */
  99.     if ((requestedProperty != pBestType) && (requestedProperty != pClass)
  100.                                             && (requestedProperty != pDefaultType))
  101.         return errAECantSupplyType;
  102.     
  103.     /* It's a legal property code, so duplicate the object's token and indicate */
  104.     /* that we want this token to represent a property.                            */
  105.     err = AEDuplicateDesc(container, returnedToken);
  106.     if (err != noErr) return err;
  107.     tokenFlags(*returnedToken) = kPropToken;
  108.     tokenPropCode(*returnedToken) = requestedProperty;
  109.  
  110.     return noErr;
  111. } /* PropertyFromEntryAccessor */
  112.  
  113.  
  114. /* This is the routine that handles creating a new item. Again, since the resources */
  115. /* aren't stored in any particular order, we're ignoring the "position" parameter.    */
  116. /* If the scrapbook ever supports putting the resources in a specific order, then     */
  117. /* this absolutely should be changed.                                                */
  118.  
  119. OSErr Item_InsertTokenData (const AERecord *insertionLoc,  const AEDescList *data,
  120.                            ResType *newTypeCode /* returned */)
  121. {
  122.     OSErr        err                  = noErr;
  123.     AEDesc        objectSpec         = {typeNull, NULL};
  124.     AEDesc        resolvedToken    = {typeNull, NULL};
  125.     short        entryNum;
  126.     
  127.     /* Extract and resolve the object specifier */
  128.     err = AEGetKeyDesc(insertionLoc, keyAEObject, typeWildCard, &objectSpec);
  129.     if (err != noErr) goto done;
  130.     if (objectSpec.descriptorType == typeNull)
  131.         return errAENoSuchObject;
  132.     err = AEResolve(&objectSpec, kAEIDoMinimum, &resolvedToken);
  133.     if (err != noErr) goto done;
  134.  
  135.     /* "resolvedToken" represents either the entry's container (the scrapbook) or */
  136.     /* another entry. In either case, the token contains the information necesary */
  137.     /* to access our particular entry in the scrapbook file.                      */
  138.     if ((resolvedToken.descriptorType != cEntry) && (resolvedToken.descriptorType != cScrapItem)) {
  139.         err = errAETypeError;
  140.         goto done;
  141.     }
  142.     
  143.     UseResFile(tokenFRefNum(resolvedToken));
  144.     entryNum = tokenObjectIndex(resolvedToken);
  145.     
  146.     /* Create the new element and put the data into it */
  147.     err = Put1ScrapbookItem(entryNum, data);
  148.  
  149. done:
  150.     if (resolvedToken.dataHandle != 0L)
  151.         (void) AEDisposeDesc(&resolvedToken);
  152.     if (objectSpec.dataHandle != 0L)
  153.         (void) AEDisposeDesc(&objectSpec);
  154.     *newTypeCode = data->descriptorType;
  155.     return err;
  156. } /* Item_InsertTokenData */
  157.  
  158.  
  159. /* This token handler takes a property or object token and returns the data  */
  160. /* represented by that token in a form which is usable to the outside world. */
  161.  
  162. OSErr Item_ReadTokenData(const AEDesc *theToken, AEDesc *tokenContents)
  163. {
  164.     DescType    propCode, objClass, typeCode;
  165.     OSErr        err            = noErr;
  166.     
  167.     /*  Get the thing pointed to by a property or object token */
  168.     objClass = tokenDispatchClass(*theToken);
  169.     if (tokenFlags(*theToken) & kPropToken) {
  170.         /* Return any readable properties */
  171.         propCode = tokenPropCode(*theToken);
  172.         
  173.         switch (propCode) {
  174.             case pClass:
  175.                 /* Tell the outside world what class this is */
  176.                 err = AECreateDesc(typeType, (Ptr)&objClass, sizeof(objClass), tokenContents);
  177.             break;
  178.  
  179.             case pBestType:
  180.             case pDefaultType:
  181.                 /* This should be the same as the resource type for the entry */
  182.                 typeCode = tokenItemType(*theToken);
  183.                 err = AECreateDesc(typeType, (Ptr)&typeCode, sizeof(typeCode), tokenContents);
  184.             break;
  185.         }
  186.     }
  187.  
  188.     else if (tokenFlags(*theToken) & kObjectToken) {
  189.         /* If you're ever asked to "read" an object's value, you should return the */
  190.         /* default type. For us, this is the same as the resource type.               */
  191.         UseResFile(tokenFRefNum(*theToken));
  192.         if ((err = ResError()) == noErr)
  193.             err = Get1ScrapbookItem(tokenObjectIndex(*theToken), tokenItemType(*theToken), tokenContents);
  194.     }
  195.     else
  196.         err = errAEEventFailed;
  197.  
  198.     return err;
  199. }
  200.  
  201. /* This token handler is used to change the value of some Item */
  202. OSErr Item_WriteTokenData(const AEDesc *theToken, const AEDesc *data)
  203. {
  204.     OSErr    err;
  205.     
  206.     /* We'll only handle a Set Data request for an Item object, and not */
  207.     /* for any of its properties.                                        */
  208.     if (tokenFlags(*theToken) == kPropToken)
  209.         err = errAENotModifiable;
  210.     else {
  211.         UseResFile(tokenFRefNum(*theToken));
  212.         if ((err = ResError()) == noErr)
  213.             err = Put1ScrapbookItem (tokenObjectIndex(*theToken), data);
  214.     }
  215.     return err;
  216. }
  217.  
  218.  
  219. /* This token handler is used to delete a particular object. */
  220. /* In this implementation, I've decided to make each object     */
  221. /* responsible for its own creation and destruction, so this */
  222. /* routine will delete a single entry (and all of its         */
  223. /* elements) from the scrapbook.                             */
  224. OSErr Item_DeleteTokenData(const AEDesc *theToken)
  225. {
  226.     OSErr    err;
  227.     Boolean    elementRemoved;
  228.     
  229.     if (theToken->descriptorType != cScrapItem) 
  230.         return errAETypeError;
  231.  
  232.     if (tokenFlags(*theToken) & kPropToken)
  233.         /* Properties may not be deleted */
  234.         return errAENotModifiable;
  235.  
  236.     /* This must be an object token, so get rid of it */
  237.     UseResFile(tokenFRefNum(*theToken));
  238.     if ((err = ResError()) == noErr)
  239.         err = Delete1ScrapbookItem(tokenObjectIndex(*theToken), tokenItemType(*theToken), &elementRemoved);
  240.         if ((err == noErr) && elementRemoved) 
  241.             /* If the element was removed, notify the window */
  242.             EntryRemoved(tokenWindow(*theToken), tokenObjectIndex(*theToken));
  243.  
  244.     return err;
  245. }
  246.  
  247.  
  248. OSErr Item_GetData(AppleEvent *message, AppleEvent *reply, long refcon,
  249.                 AEDesc *token, AEDesc *replyObject)
  250. {
  251.     return Item_ReadTokenData(token, replyObject);
  252. } /* Item_GetData */
  253.  
  254.  
  255. OSErr Item_SetData(AppleEvent *message, AppleEvent *reply, long refcon,
  256.                 AEDesc *token, AEDesc *replyObject)
  257. {
  258.     AEDesc    theData;
  259.     OSErr    err;
  260.  
  261.     err = AEGetKeyDesc(message, keyAEData, typeWildCard, &theData);
  262.     if (err == noErr) {
  263.         /*  We don't handle passing in the data as an object specifier */
  264.         if (theData.descriptorType == typeObjectSpecifier) {
  265.             return errAECantHandleClass;
  266.         }
  267.         err = Item_WriteTokenData(token, &theData);
  268.         (void)AEDisposeDesc(&theData);
  269.         InvalidateWindow(tokenWindow(*token));    /* Make sure the item gets re-drawn */
  270.     }
  271.     return err;
  272. } /* Item_SetData */
  273.  
  274.  
  275. OSErr Item_CreateElement(AppleEvent *message, AppleEvent *reply, long refcon,
  276.                 AEDesc *token, AEDesc *replyObject)
  277. {
  278.     OSErr        err = noErr;
  279.     AEDesc        data         = {typeNull, NULL};
  280.     AERecord    insertionLoc = {typeNull, NULL};
  281.     ResType        newItemType;
  282.     
  283.     /* Extract the insertionLoc record and have the Apple Event Manager coerce it into    */
  284.     /* an AERecord for us.                                                                 */
  285.     err = AEGetParamDesc(message, keyAEInsertHere, typeAERecord, &insertionLoc);
  286.     if (err != noErr) goto done;
  287.  
  288.     /* Extract the optional data */
  289.     err = AEGetParamDesc(message, keyAEData, typeWildCard, &data);
  290.     /* Since this is an optional parameter, don't exit if the keyword wasn't found */
  291.     if ((err != noErr) && (err != errAEDescNotFound)) goto done;
  292.     
  293.     /* Create the element */
  294.     err = Item_InsertTokenData(&insertionLoc, &data, &newItemType);
  295.     if (err != noErr) goto done;
  296.     /* <<< Construct an object specifier for the new entry and return it here */
  297.  
  298. done:
  299.     if (insertionLoc.dataHandle != 0)
  300.         (void) AEDisposeDesc(&insertionLoc);
  301.         
  302.     if (data.dataHandle != 0)
  303.         (void) AEDisposeDesc(&data);
  304.  
  305.     return err;
  306. } /* Item_CreateElement */
  307.  
  308.  
  309. OSErr Item_DeleteElement(AppleEvent *message, AppleEvent *reply, long refcon,
  310.                 AEDesc *token, AEDesc *replyObject)
  311. {
  312.     return Item_DeleteTokenData(token);
  313. } /* Item_DeleteElement */
  314.  
  315.  
  316. OSErr Item_AE_Dispatcher(const AppleEvent *message, AppleEvent *reply, long refCon,
  317.                         AEEventClass classID, AEEventID eventID,
  318.                         const AEDesc *ospec, const AEDesc *token)
  319. {
  320.     OSErr    err = noErr;
  321.     AEDesc    replyDesc = {'null', 0L};
  322.  
  323.     if (classID == kAECoreSuite) {
  324.         switch (eventID) {
  325.             case kAECreateElement:
  326.                 err =  Item_CreateElement(message, reply, refCon, token, &replyDesc);
  327.             break;
  328.  
  329.             case kAEDelete:
  330.                 err = Item_DeleteElement(message, reply, refCon, token, &replyDesc);
  331.             break;
  332.  
  333.             case kAEGetData:
  334.                 err =  Item_GetData(message, reply, refCon, token, &replyDesc);
  335.             break;
  336.  
  337.             case kAEGetDataSize: {
  338.                 /*  We'll do this one by executing "Get Data" and then returning the  */
  339.                 /*  size of the information. This is not necesarily the most efficient */
  340.                 /*  way to do things if your returned data is large, but the alternatives. */
  341.                 /*  are pretty difficult */
  342.                 AEDesc    tempDesc = {'null', NULL};
  343.                 long    dataSize;
  344.                 
  345.                 err = Item_GetData(message, reply, refCon, token, &tempDesc);
  346.                 if (tempDesc.dataHandle != NULL) {
  347.                     dataSize = GetHandleSize(tempDesc.dataHandle);
  348.                     (void)AECreateDesc(typeLongInteger, (Ptr)&dataSize, sizeof(dataSize), &replyDesc);
  349.                     (void)AEDisposeDesc(&tempDesc);
  350.                 }
  351.             }
  352.             break;
  353.  
  354.             case kAESetData:
  355.                 err =  Item_SetData(message, reply, refCon, token, &replyDesc);
  356.             break;
  357.  
  358.             case kAEClone:
  359.             case kAECountElements:
  360.             case kAEDoObjectsExist:
  361.             case kAEGetClassInfo:
  362.             case kAEMove:
  363.             default:
  364.                 err = errAEEventNotHandled ;
  365.         }
  366.     }
  367.     else
  368.         err = errAEEventNotHandled;
  369.  
  370.     /* See if we need to return anything */
  371.     if ((err == noErr) && (replyDesc.descriptorType != 'null')
  372.             && (reply->descriptorType != 'null')) {    /* Note: if the other side didn't ask for a reply, this could be a null desc */
  373.             err = AEPutParamDesc(reply, keyDirectObject, &replyDesc);
  374.             (void)AEDisposeDesc(&replyDesc);
  375.     }
  376.  
  377.     return err;
  378. } /* Item_AE_Dispatcher */
  379.  
  380.